package vg.modules.opener;

import org.apache.tools.ant.filters.StringInputStream;
import tzhomestudio.framework.shared.utils.FileUtils;
import vg.interfaces.ll_services.data_base_service.data.header.GraphModelHeader;
import vg.services.main_manager.VGMainServiceHelper;
import vg.services.plugin_manager.event_and_request.event.UIEventOpenNewGraph;
import vg.services.plugin_manager.event_and_request.request.AUIRequest;
import vg.services.plugin_manager.event_and_request.request.UIRequestLoadProject;
import vg.services.plugin_manager.event_and_request.request.UIRequestSaveProject;
import vg.services.plugin_manager.event_and_request.request.VGOpenGraphRequest;
import vg.services.plugin_manager.interfaces.IPlugin;
import vg.services.user_interface_manager.interfaces.UserInterfaceObserverAdapter;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;

public class GraphOpenerPlugin implements IPlugin {
	// Swing components
    private JFileChooser fileChooser;

	// Defines
	private final static String DEF_LAST_OPEN_GRAPH_DIR = "GRAPH_OPENER_LastDir";

    /**
	 * Installer.
	 */
	public void install() {
        final JMenuItem jMenuItem = new JMenuItem("Open file");
		jMenuItem.setIcon(new ImageIcon("./data/resources/textures/openFile.png"));
		//---------------------------------------
		jMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openGraph();
			}
		});
		jMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		//---------------------------------------
        VGMainServiceHelper.userInterfaceManager.addMenuItem(jMenuItem, "file");
        VGMainServiceHelper.userInterfaceManager.addObserver(new UserInterfaceObserverAdapter() {
            @Override
            public void dispatchRequest(AUIRequest request) {
                switch(request.getType()) {
                    case DEF_SAVE_PROJECT: {
                        UIRequestSaveProject buf = (UIRequestSaveProject)request;
                        saveProject(buf.getPath());
                        break;
                    }

                    case DEF_LOAD_PROJECT: {
                        final UIRequestLoadProject buf = (UIRequestLoadProject)request;
                        VGMainServiceHelper.threadPoolManager.submit(new Runnable() {
                            public void run() {
                                loadProject(buf.getPath());
                            }
                        });
                        break;
                    }

                    case DEF_OPEN_GRAPH:
                        openGraphRequest((VGOpenGraphRequest) request);
                        break;

                    default: break;
                }
            }
        });

        fileChooser = new JFileChooser(".");

        for (final String ext : ConsoleOpener.getAvailableExtensions()) {
        	fileChooser.addChoosableFileFilter(new FileFilter() {
				@Override
                public String getDescription() {
					return ext + " file (*." + ext +")";
				}

                @Override
                public boolean accept(File f) {
					return f != null && (f.isDirectory() || f.getName().toLowerCase().endsWith(ext));
				}
			});
        }
	}

//==============================================================================
//------------------PRIVATE METHODS---------------------------------------------
    private void openGraphRequest(final VGOpenGraphRequest vgOpenGraphRequest) {
        VGMainServiceHelper.threadPoolManager.submit(new Runnable() {
            public void run() {
                doOpenGraphRequest(vgOpenGraphRequest);
            }
        });
    }

    private void doOpenGraphRequest(VGOpenGraphRequest vgOpenGraphRequest) {
        String fileName = vgOpenGraphRequest.getName() + "." + vgOpenGraphRequest.getFormat();
        File tmpFile = FileUtils.createTmpFileWithName(fileName);
        try {
            ReadableByteChannel rbc = Channels.newChannel(new StringInputStream(vgOpenGraphRequest.getContent()));
            FileOutputStream fos = new FileOutputStream(tmpFile);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        } catch (FileNotFoundException ex) {
            VGMainServiceHelper.logger.printException(ex);
            VGMainServiceHelper.windowMessenger.errorMessage("Can't create file: " + tmpFile.getAbsolutePath(), "Error");
        } catch (IOException ex) {
            VGMainServiceHelper.logger.printException(ex);
            VGMainServiceHelper.windowMessenger.errorMessage("Can't write to file: " + tmpFile.getAbsolutePath(), "Error");
        }

        // open graph
        doOpenGraph(tmpFile);
    }

	private void openGraph() {
        // set last directory for file chooser
        String lastDir = VGMainServiceHelper.config.getProperty(GraphOpenerPlugin.DEF_LAST_OPEN_GRAPH_DIR);
        if(lastDir != null) {
            fileChooser.setCurrentDirectory(new File(lastDir));
        }

        // update file chooser interface
        fileChooser.updateUI();

        // show it
		if (fileChooser.showOpenDialog(VGMainServiceHelper.userInterfaceManager.getMainFrame()) == JFileChooser.APPROVE_OPTION) {
            VGMainServiceHelper.logger.printDebug("[" + this.getClass().getName() + ".openGraph] [PROCESS] Open file = " + fileChooser.getSelectedFile().getPath());
            VGMainServiceHelper.config.setProperty(GraphOpenerPlugin.DEF_LAST_OPEN_GRAPH_DIR, fileChooser.getCurrentDirectory().getAbsolutePath());
            doOpenGraph(fileChooser.getSelectedFile());
		}
	}

    private void doOpenGraph(final File file) {
        VGMainServiceHelper.threadPoolManager.submit(new Runnable() {
            public void run() {
                try {
                    List<Integer> newGraphModelIds = ConsoleOpener.openFile(file, VGMainServiceHelper.graphDataBaseManager);

                    VGMainServiceHelper.logger.printDebug("[" + this.getClass().getName() + ".openGraph] [OK] Open file = " + file.getAbsolutePath());
                    if(newGraphModelIds == null || newGraphModelIds.isEmpty()) {
                        VGMainServiceHelper.windowMessenger.errorMessage("Can't open file. May be file is empty", "Error");
                    } else {
                        for(Integer buf : newGraphModelIds) {
                            GraphModelHeader gh = VGMainServiceHelper.graphDataBaseManager.getGraphModelHeader(buf);
                            if(gh != null) {
                                UIEventOpenNewGraph ong = new UIEventOpenNewGraph(buf, gh.getName());
                                VGMainServiceHelper.userInterfaceManager.sendEvent(ong);
                            } else {
                                VGMainServiceHelper.windowMessenger.errorMessage("Can't open file. Database error", "Error");
                            }
                        }
                    }
                } catch (Throwable e) {
                    VGMainServiceHelper.logger.printException(e);
                    VGMainServiceHelper.windowMessenger.errorMessage("Can't open file: " + file.getAbsolutePath(), "Error");
                }
            }
        });

    }

	/**
	 * This method saves all files, which contain 
	 * graphs and were used by user.
	 */
	private void saveProject(String path) {
		ArrayList<String> dontSavedFiles = new ArrayList<String>();	
		for (String fileName : ConsoleOpener.getOpenedFilesList()) {
			try {
				File oldFile = new File(fileName);
				File newFile = new File(path + File.separator + oldFile.getName());
				//we don't want have problems with coping file into itself
				if (oldFile.compareTo(newFile) == 0) {
					continue;
				}
				FileChannel originalGraphFile = new FileInputStream(oldFile).getChannel();
				FileChannel copyFile = new FileOutputStream(newFile).getChannel();
				try {
					originalGraphFile.transferTo(0, originalGraphFile.size(), copyFile);
				} catch (IOException e1) {
                    VGMainServiceHelper.logger.printException(e1);
				} finally {
					if (originalGraphFile != null) 
						originalGraphFile.close();
					if (copyFile != null)
						copyFile.close();
				}
			} catch (IOException e1) {
                VGMainServiceHelper.logger.printException(e1);
				dontSavedFiles.add(fileName);
			}						
		}

        // show warning
		if (!dontSavedFiles.isEmpty()) {
			StringBuilder warningMessage = new StringBuilder("Could not save these files:");
			for (String it : dontSavedFiles) {
				warningMessage.append("\n");
				warningMessage.append(it);
			}

            VGMainServiceHelper.windowMessenger.warningMessage(warningMessage.toString(), "Save project");
		}
	}

	/**
	 * This method loads all files, which contain 
	 * graphs and were used by user.
	 */
	private void loadProject(String path) {
		File dir = new File(path);
		if(dir.exists() && dir.isDirectory()) {		
			ArrayList<String> dontOpenedFiles = new ArrayList<String>();	
			for (String fileName : dir.list()) {
				String filePath = dir.getPath() + File.separator + fileName;
				for (final String ext : ConsoleOpener.getAvailableExtensions())
					if (filePath.toLowerCase().endsWith(ext)) {
						// TODO Need save to vgdb file and read from it.
/*						try {						
							int newGraphId = ConsoleOpener.openFile(filePath, this.parameter.model);
							GraphHeader gh = parameter.model.getGraphHeader(newGraphId);
							if(gh != null) {
								UIEventOpenNewGraph ong = new UIEventOpenNewGraph(newGraphId, gh.name);
								parameter.userInterfaceManager.addEvent(ong);
							} else {
								VisualGraph.windowMessage.errorMessage("Can't open file. Database error.", "Error");							
							}							
						} catch (CoreException e) {
							VisualGraph.logger.printException(e);
							dontOpenedFiles.add(filePath);						
						}
*/					}
			}
			if (!dontOpenedFiles.isEmpty()) {
				StringBuilder warningMessage = new StringBuilder("Could not open file\n");
				for (String doesntOpenedFile : dontOpenedFiles) {
					warningMessage.append("\n");
					warningMessage.append(doesntOpenedFile);
				}
                VGMainServiceHelper.windowMessenger.warningMessage(warningMessage.toString(), "Open project");
			}
		} else {
            VGMainServiceHelper.logger.printError("[" + this.getClass().getName() + ".loadProject] is not directory (or not exist)");
		}
	}
}
